package com.tanhua.manager.service;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.date.DateField;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.dubbo.config.annotation.Reference;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.tanhua.common.mapper.UserInfoMapper;
import com.tanhua.common.pojo.UserInfo;
import com.tanhua.dubbo.api.DashboardApi;
import com.tanhua.dubbo.pojo.BaseDistribution;
import com.tanhua.manager.enums.AgeRangeEnum;
import com.tanhua.manager.enums.AreaEnum;
import com.tanhua.manager.enums.SexEnum;
import com.tanhua.manager.vo.ManagementDistributionVo;
import com.tanhua.manager.vo.ManagementSummaryVo;
import com.tanhua.manager.vo.ManagementUsersVo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.stereotype.Service;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;

@Service
public class DashboardService {
    @Autowired
    private UserInfoMapper userInfoMapper;

    @Reference
    private DashboardApi dashboardApi;

    /**
     * 用户分布情况
     *
     * @param sd
     * @param ed
     * @return
     */
    public ManagementDistributionVo dashboardDistribution(String sd, String ed) {
        //返回对象
        ManagementDistributionVo managementDistributionVo = new ManagementDistributionVo();

        //解析时间
        DateTime sdp = DateTime.of(Convert.toLong(sd));
        DateTime edp = DateTime.of(Convert.toLong(ed));

        //根据性别查询
        List<BaseDistribution> genderDistribution = new ArrayList<>();
        BaseDistribution manDistributions = getGenderDistribution(SexEnum.MAN, sdp, edp);
        BaseDistribution womanDistributions = getGenderDistribution(SexEnum.WOMAN, sdp, edp);
        //加入集合
        genderDistribution.add(manDistributions);
        genderDistribution.add(womanDistributions);

        //根据年龄查询
        List<BaseDistribution> ageRangeList = getAgeRangeDistribution(sdp, edp);

        //根据省份查询
        List<BaseDistribution> areaList = getLocalDistribution(sdp, edp);

        //根据区域查询
        List<BaseDistribution> localTotalList = getLocalTotal(sdp, edp);

        //根据行业查询 top10
        List<BaseDistribution> industryList = getIndustryDistribution(sdp, edp);

        //加入返回对象
        managementDistributionVo.setIndustryDistribution(industryList);
        managementDistributionVo.setLocalTotal(localTotalList);
        managementDistributionVo.setLocalDistribution(areaList);
        managementDistributionVo.setAgeDistribution(ageRangeList);
        managementDistributionVo.setGenderDistribution(genderDistribution);

        return managementDistributionVo;
    }

    /**
     * 根据行业 top10
     */
    private List<BaseDistribution> getIndustryDistribution(DateTime sdp, DateTime edp) {
        //查询时间区间
        LambdaQueryWrapper<UserInfo> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.between(UserInfo::getCreated, sdp, edp);
        List<UserInfo> userInfoList = userInfoMapper.selectList(queryWrapper);

        //map key：行业  value：数量
        HashMap<String, Integer> map = new HashMap<>();
        //遍历
        for (UserInfo userInfo : userInfoList) {
            String industry = userInfo.getIndustry();
            if (map.containsKey(industry)) {
                Integer count = map.get(industry);
                count++;
                map.put(industry, count);
            } else {
                map.put(industry, 1);
            }
        }
        //map 装入 list
        List<BaseDistribution> industryList = new ArrayList<>();
        Set<String> keySet = map.keySet();
        for (String s : keySet) {
            BaseDistribution baseDistribution = new BaseDistribution();
            baseDistribution.setTitle(s);
            baseDistribution.setAmount(map.get(s));
            industryList.add(baseDistribution);
        }
        //排序
        CollUtil.sort(industryList, (o1, o2) -> {
            //降序
            return o2.getAmount().compareTo(o1.getAmount());
        });
        //取前10，不够取最大索引
        int index = Math.min(10, industryList.size());
        return industryList.subList(0, index);
    }

    /**
     * 区域
     *
     * @param sdp
     * @param edp
     * @return
     */
    //
    private List<BaseDistribution> getLocalTotal(DateTime sdp, DateTime edp) {
        //调用查询省份方法
        List<BaseDistribution> localDistribution = getLocalDistribution(sdp, edp);
        //map 装地区数据
        HashMap<String, Integer> map = new HashMap<>();

        for (BaseDistribution distribution : localDistribution) {
            String province = distribution.getTitle();
            String area = AreaEnum.getAreaByProvince(province);
            Integer amount = distribution.getAmount();
            if (map.containsKey(area)) {//地区存在，累加数值
                Integer count = map.get(area);
                count += amount;
                map.put(area, count);
            } else {//地区不存在，添加
                map.put(area, amount);
            }
        }
        //创建集合 装地区对象
        List<BaseDistribution> areaTotalList = new ArrayList<>();
        //遍历map
        Set<String> keySet = map.keySet();
        for (String s : keySet) {
            BaseDistribution localTotal = new BaseDistribution();
            localTotal.setTitle(s);
            localTotal.setAmount(map.get(s));
            areaTotalList.add(localTotal);
        }

        return areaTotalList;
    }


    /**
     * //省份
     *
     * @param sdp
     * @param edp
     * @return
     */
    private List<BaseDistribution> getLocalDistribution(DateTime sdp, DateTime edp) {
        //创建集合
        List<BaseDistribution> areaRangeList = new ArrayList<>();

        for (int i = 0; i < AreaEnum.values().length; i++) {
            //对象
            BaseDistribution localDistribution = new BaseDistribution();
            //枚举项
            AreaEnum[] values = AreaEnum.values();
            //查询
            LambdaQueryWrapper<UserInfo> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.like(UserInfo::getCity, values[i].getProvince())//省份
                    .between(UserInfo::getCreated, sdp, edp);//时间区间
            Integer count = userInfoMapper.selectCount(queryWrapper);//统计个数

            //区域
            String area = AreaEnum.getAreaByProvince(values[i].getProvince());

            //封装
            localDistribution.setTitle(values[i].getProvince());
            localDistribution.setAmount(count);
            //添加
            areaRangeList.add(localDistribution);
        }
        return areaRangeList;
    }

    /**
     * //年龄
     *
     * @param sdp
     * @param edp
     * @return
     */

    //年龄
    private List<BaseDistribution> getAgeRangeDistribution(DateTime sdp, DateTime edp) {

        //创建集合
        List<BaseDistribution> ageRangeList = new ArrayList<>();
        //遍历枚举
        for (int i = 0; i < AgeRangeEnum.values().length; i++) {
            //创建对象
            BaseDistribution ageDistribution = new BaseDistribution();
            //获取枚举
            AgeRangeEnum[] values = AgeRangeEnum.values();
            //查询
            LambdaQueryWrapper<UserInfo> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.between(UserInfo::getAge, values[i].getMin(), values[i].getMax())//年龄
                    .between(UserInfo::getCreated, sdp, edp);//时间区间
            Integer conut = userInfoMapper.selectCount(queryWrapper);//统计个数
            //封装
            ageDistribution.setTitle(values[i].getDesc());
            ageDistribution.setAmount(conut);
            //添加
            ageRangeList.add(ageDistribution);
        }
        return ageRangeList;

    }



    /**
     * //查询 性别
     *
     * @param gender
     * @param sdp
     * @param edp
     * @return
     */

    //查询 性别
    private BaseDistribution getGenderDistribution(SexEnum gender, DateTime sdp, DateTime edp) {

        LambdaQueryWrapper<UserInfo> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(UserInfo::getSex, gender)//性别
                .between(UserInfo::getCreated, sdp, edp);//时间区间
        Integer conut = userInfoMapper.selectCount(queryWrapper);//统计个数
        //封装行业对象
        BaseDistribution genderDistribution = new BaseDistribution();
        genderDistribution.setTitle(gender.toString());
        genderDistribution.setAmount(conut);

        return genderDistribution;
    }

    /**
     * 新增、活跃用户、次日留存率
     *
     * @param sd
     * @param ed
     * @param type
     * @return
     */
    public ManagementUsersVo dashboardUsers(String sd, String ed, String type) throws Exception {
        //解析时间
        DateTime sdp = DateTime.of(Convert.toLong(sd));
        DateTime edp = DateTime.of(Convert.toLong(ed));

        int yearEd = edp.year(); //结束年份
        int yearSd = yearEd - 1;//去年年份

        //页面对象
        ManagementUsersVo managementUsersVo = new ManagementUsersVo();
        //新增用户
        if (StrUtil.equals(type, "101")) {
            //查询月份统计
            //去年的时间
            ArrayList<BaseDistribution> countByMonthLast = getBaseDistributionList(yearSd);
            managementUsersVo.setLastYear(countByMonthLast);

            //结束年的时间
            ArrayList<BaseDistribution> countByMonthThis = getBaseDistributionList(yearEd);
            managementUsersVo.setThisYear(countByMonthThis);
        }
        if (StrUtil.equals(type, "102")) { //活跃用户
            //去年的时间
            ArrayList<BaseDistribution> lastYear = getBaseDistributions(yearSd);
            managementUsersVo.setLastYear(lastYear);

            //结束年的时间
            ArrayList<BaseDistribution> thisYear = getBaseDistributions(yearEd);
            managementUsersVo.setThisYear(thisYear);
        }

        if (StrUtil.equals(type, "103")) { //留存率
            //留存率
            ArrayList<BaseDistribution> list = new ArrayList<>();

            //每月新增
            ArrayList<BaseDistribution> thisYearCreated = getBaseDistributionList(yearEd);
            //每月活跃
            ArrayList<BaseDistribution> thisYearActive = getBaseDistributions(yearEd);

            for (BaseDistribution created : thisYearCreated) {
                BaseDistribution rateObject = new BaseDistribution();
                String createdTitle = created.getTitle();
                Integer createdAmount = created.getAmount();
                for (BaseDistribution active : thisYearActive) {
                    String activeTitle = active.getTitle();
                    Integer activeAmount = active.getAmount();
                    if (StrUtil.equals(createdTitle,activeTitle)){
                        if(activeAmount!=0) {
                            Integer rate = (createdAmount - activeAmount) * 100 / activeAmount;
                            rateObject.setTitle(createdTitle);
                            rateObject.setAmount(rate);
                            list.add(rateObject);
                            managementUsersVo.setThisYear(list);
                        }else {
                            managementUsersVo.setThisYear(null);
                        }
                    }
                }
            }



        }
        return managementUsersVo;
    }

    /**
     * 按月查询 mongodb
     * @param year
     * @return
     * @throws ParseException
     */
    private ArrayList<BaseDistribution> getBaseDistributions(int year) throws ParseException {
        // 循环 12个月
        ArrayList<BaseDistribution> lastYear = new ArrayList<>();
        for (int i = 1; i <= 12; i++) {
            //每月起始时间
            String sdLastMonth = year + "-" + i + "-1 00:00:01";
            String edLastMonth = year + "-" + i + "-" + DateUtil.lengthOfMonth(i, true) + " 23:59:59";
            //转为毫秒值
            long timeSd = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse(sdLastMonth).getTime();
            long timeEd = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse(edLastMonth).getTime();
            int month = i;
            BaseDistribution countMonth = dashboardApi.getCountMonth(timeSd, timeEd, i);
            lastYear.add(countMonth);
        }
        return lastYear;
    }

    /**按月查询 mysql
     *
     * @param year
     * @return
     * @throws ParseException
     */
    private ArrayList<BaseDistribution> getBaseDistributionList(int year) throws ParseException {
        // 循环 12个月
        ArrayList<BaseDistribution> lastYear = new ArrayList<>();
        for (int i = 1; i <= 12; i++) {
            //每月起始时间
            String sdLastMonth = year + "-" + i + "-1 00:00:01";
            String edLastMonth = year + "-" + i + "-" + DateUtil.lengthOfMonth(i, true) + " 23:59:59";
            //转为datetime
            DateTime timeSd = DateTime.of(sdLastMonth, "yyyy-MM-dd HH:mm:ss");
            DateTime timeEd = DateTime.of(edLastMonth, "yyyy-MM-dd HH:mm:ss");

            //long timeSd = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse(sdLastMonth)
            //long timeEd = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse(edLastMonth).getTime();
            int month = i;
            BaseDistribution countMonth = getCountByMonth(timeSd, timeEd, i);
            lastYear.add(countMonth);
        }
        return lastYear;
    }


    /**
     * 查询每月数量 mysql
     *
     * @param sdp
     * @param edp
     */
    private BaseDistribution getCountByMonth(DateTime sdp, DateTime edp,int month) {
        //查询时间区间的用户信息
        LambdaQueryWrapper<UserInfo> query=new LambdaQueryWrapper<>();
        query.between(UserInfo::getCreated,sdp,edp);
        List<UserInfo> userInfoList = userInfoMapper.selectList(query);

        BaseDistribution baseDistribution = new BaseDistribution();
        baseDistribution.setTitle(month + "月");
        baseDistribution.setAmount(userInfoList.size());

        return baseDistribution;
    }

    /**
     * 概要统计信息
     */
    public ManagementSummaryVo dashboardSummary() {
        //对象，存储vo数据
        ManagementSummaryVo managementSummaryVo = new ManagementSummaryVo();

        //1--累计用户
        Wrapper<UserInfo> query = new QueryWrapper<>();
        Integer userInfoTotal = userInfoMapper.selectCount(query);

        //2--过去30天活跃用户

        Integer countActive30 = dashboardApi.getCountActive(getStartTime(-30).getTime(), getEndTime(0).getTime());
        System.out.println(getStartTime(-30)+"---->"+getEndTime(0));
        //3--过去7天活跃用户

        Integer countActive7 = dashboardApi.getCountActive(getStartTime(-7).getTime(), getEndTime(0).getTime());
        System.out.println(getStartTime(-7)+"---->"+getEndTime(0));
        //4--今日新增用户
        Integer userCreatedSum = getUserCreatedSum(0);

        //5--今日新增用户涨跌率，单位百分数，正数为涨，负数为跌
        //昨日数据
        Integer userCreatedSumYesterday = getUserCreatedSum(-1);

        if (userCreatedSumYesterday != 0) {
            //百分比 除数不为0
            Integer userCreatedRate = ((userCreatedSum - userCreatedSumYesterday) * 100/ userCreatedSumYesterday) ;
            managementSummaryVo.setNewUsersTodayRate(userCreatedRate);
        } else {
            managementSummaryVo.setNewUsersTodayRate(null);
        }

        //6--今日登录次数
        Integer countLoginToday = dashboardApi.getCountLogin(getStartTime(0).getTime(), getEndTime(0).getTime());

        //7--今日登录次数涨跌率，单位百分数，正数为涨，负数为跌
        //昨日数据
        Integer countLoginYesterday = dashboardApi.getCountLogin(getStartTime(-1).getTime(), getEndTime(-1).getTime());

        if (countLoginYesterday != 0) {
            //百分比 除数不为0
            Integer loginTimesTodayRate = ((countLoginToday - countLoginYesterday)* 100 / countLoginYesterday) ;
            managementSummaryVo.setLoginTimesTodayRate(loginTimesTodayRate);
        } else {
            managementSummaryVo.setLoginTimesTodayRate(null);
        }


        //10--过去7天平均日使用时长，单位秒
        managementSummaryVo.setUseTimePassWeek(33333);

        //11--昨日活跃用户
        Integer countActiveYesterday = dashboardApi.getCountActive(getStartTime(-1).getTime(), getEndTime(-1).getTime());

        //12--昨日活跃用户涨跌率，单位百分数，正数为涨，负数为跌
        //前日数据
        Integer countActiveBeforeYesterday = dashboardApi.getCountActive(getStartTime(-2).getTime(), getEndTime(-2).getTime());

        if (countActiveBeforeYesterday != 0) {
            //百分比 除数不为0
            Integer countActiveYesterdayRate = ((countActiveYesterday - countActiveBeforeYesterday) * 100/ countActiveBeforeYesterday) ;
            managementSummaryVo.setActiveUsersYesterdayRate(countActiveYesterdayRate);
        } else {
            managementSummaryVo.setActiveUsersYesterdayRate(null);
        }

        //8--今日活跃用户
        Integer countActiveToday = dashboardApi.getCountActive(getStartTime(0).getTime(), getEndTime(0).getTime());

        //9--今日活跃用户涨跌率，单位百分数，正数为涨，负数为跌
        if (countActiveYesterday != 0) {
            //百分比 除数不为0
            Integer countActiveTodayRate = ((countActiveToday - countActiveYesterday)  * 100/ countActiveYesterday);
            managementSummaryVo.setActiveUsersTodayRate(countActiveTodayRate);
        } else {
            managementSummaryVo.setActiveUsersTodayRate(null);
        }

        managementSummaryVo.setActiveUsersToday(countActiveToday);
        managementSummaryVo.setActiveUsersYesterday(countActiveYesterday);
        managementSummaryVo.setLoginTimesToday(countLoginToday);
        managementSummaryVo.setNewUsersToday(userCreatedSum);
        managementSummaryVo.setActivePassWeek(countActive7);
        managementSummaryVo.setActivePassMonth(countActive30);
        managementSummaryVo.setCumulativeUsers(userInfoTotal);

        return managementSummaryVo;
    }

    /**
     * 获得创建用户数 mysql
     *
     * @return
     */
    private Integer getUserCreatedSum(Integer offset) {

        LambdaQueryWrapper<UserInfo> queryWrapperRate = new LambdaQueryWrapper<>();
        queryWrapperRate.between(UserInfo::getCreated, getStartTime(offset), getEndTime(offset));
        List<UserInfo> userInfoList = userInfoMapper.selectList(queryWrapperRate);

        int userCreatedSum = userInfoList.size();
        return userCreatedSum;
    }

    /**
     * 开始时间
     *
     * @param offset
     * @return
     */
    private DateTime getStartTime(Integer offset) {
        String s = DateTime.now().offset(DateField.DAY_OF_MONTH, offset).toString("yyyy-MM-dd");
        DateTime startTime = DateTime.of(s + " 00:00:01", "yyyy-MM-dd HH:mm:ss");
        return startTime;
    }

    /**
     * 结束时间
     *
     * @param offset
     * @return
     */
    private DateTime getEndTime(Integer offset) {
        String s = DateTime.now().offset(DateField.DAY_OF_MONTH, offset).toString("yyyy-MM-dd");
        DateTime endTime = DateTime.of(s + " 23:59:59", "yyyy-MM-dd HH:mm:ss");
        return endTime;
    }
}
